package com.capsulode.excel.conversion;

import com.capsulode.excel.annotation.Header;
import com.capsulode.excel.conversion.impl.*;
import com.capsulode.excel.exception.UnsupportedConversionException;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class ConverterManager {
    private static final ThreadLocal<ConverterManager> instance = ThreadLocal.withInitial(ConverterManager::new);

    public static ConverterManager getThreadLocalInstance() {
        return instance.get();
    }

    public static void evictThreadLocal() {
        instance.remove();
    }

    private final Map<String, Converter> converters = new HashMap<>();

    private ConverterManager() {
        registerStandardConverters();
    }

    private void registerStandardConverters() {
        registerConverter(String.class, new StringConverter());
        registerConverter(Integer.class, new IntegerConverter());
        registerConverter(Integer.TYPE, new IntegerConverter());
        registerConverter(Long.class, new LongConverter());
        registerConverter(Long.TYPE, new LongConverter());
        registerConverter(Double.class, new DoubleConverter());
        registerConverter(Double.TYPE, new DoubleConverter());
        registerConverter(Boolean.class, new BooleanConverter());
        registerConverter(Boolean.TYPE, new BooleanConverter());
        registerConverter(Object.class, new ObjectConverter());
    }

    public <T> void registerConverter(Class<T> type, Converter<T> converter) {
        converters.put(type.getName(), converter);
    }

    public <T> void deregisterConverter(Class<T> type) {
        converters.remove(type.getName());
    }

    /**
     * @deprecated use {@link #newConverter(Class, Header)} instead.
     */
    public <T> Converter<T> getConverter(Class<T> type) {
        return converters.get(type.getName());
    }

    public static Converter newConverter(Class type, Header headerDefine) throws UnsupportedConversionException {
        if (headerDefine != null) {
            if (Date.class.isAssignableFrom(type)) {
                return new DateConverter(headerDefine.pattern());
            }
            if (headerDefine.dictionary().length > 0) {
                return new DictionaryConverter(headerDefine.dictionary(), type);
            }
            if (!headerDefine.currency().equals(Header.Currency.NONE)) {
                switch (headerDefine.currency()) {
                    case RMB:
                        return new RmbConverter(type);
                    default:
                        throw new UnsupportedConversionException(headerDefine.currency().getClass());
                }
            }
        }

        Converter converter = getThreadLocalInstance().converters.get(type.getName());
        if (converter == null) {
            throw new UnsupportedConversionException(type);
        }

        return converter;

    }
}
